#include "gd32f1x0.h"
#include "main.h"
#include "stdio.h"
#include "string.h"
#include "debug.h"
#include "hwlayer.h"
#include "config.h"
#include "stdlib.h"
#include "mystring.h"
#include "mwl_device.h"
#if (DEBUG_EN == 1)
unsigned char debug_buf[32];
unsigned char debug_cnt = 0;
unsigned char debug_level = 0;
unsigned char debug_en = 0;
unsigned char isCmdEnable = 0;
unsigned char isAdcDumpEn = 0;
unsigned short int AdcDumpCount = 32;

#define DEBUG_SAVE_EN(x) hwl_iic_writeReg(CONFIG_MAP_BLANK_HEAD, x)
#define DEBUG_SAVE_LEVEL(x) hwl_iic_writeReg(CONFIG_MAP_BLANK_HEAD + 1, x)

#define DEBUG_LOAD()                                            \
    do                                                          \
    {                                                           \
        hwl_iic_init();                                         \
        hwl_iic_read(CONFIG_MAP_BLANK_HEAD, debug_buf, 2);      \
        debug_en = debug_buf[0];                                \
        debug_level = debug_buf[1];                             \
        gCfg_u.memory[CONFIG_MAP_BLANK_HEAD] = debug_en;        \
        gCfg_u.memory[CONFIG_MAP_BLANK_HEAD + 1] = debug_level; \
    } while (0)
/*
*调试工具任务，可以通过这个任务来实时获取设备各项参数
*/
unsigned char retryCnt = 0;
void debu_process(void)
{
    if (strncmp("114514", (const char *)debug_buf, 6) == 0)
    {
        isCmdEnable = 1;
        printf("log:");
        if (debug_en == 0xAA)
        {
            printf("enabled,");
        }
        else
        {
            printf("disabled,");
        }
        switch (debug_level)
        {
        case DEBUG_INFO:
            printf("info.\r\n");
            break;
        case DEBUG_NONE:
            printf("none.\r\n");
            break;
        case DEBUG_WARN:
            printf("warning.\r\n");
            break;
        case DEBUG_ERROR:
            printf("error.\r\n");
            break;
        default:
            printf("unknow.\r\n");
            break;
        }
        return;
    }

    if (isCmdEnable == 0)
    {
        retryCnt++;
        if (retryCnt == 5)
        {
            hwl_delay_ms(5000);
            retryCnt = 0;
        }
    }

    if (isCmdEnable)
    {
        if (strncmp("eeprom erase", (const char *)debug_buf, 12) == 0)
        {
            printf("[DEBUG] Erasing EEPROM.\r\n");
            hwl_iic_reset();
        }
        else if (strncmp("eeprom dump", (const char *)debug_buf, 11) == 0)
        {
            unsigned char tmp;
            printf("[DEBUG] Dump EEPROM.\r\n    ");
            for (tmp = 0; tmp < 32; tmp++)
            {
                printf("%2d  ", tmp);
            }
            for (debug_cnt = 0; debug_cnt < 8; debug_cnt++)
            {
                unsigned short t = 0;
                hwl_iic_read(debug_cnt * 32, debug_buf, 32);
                printf("\r\n%3d:", debug_cnt * 32);
                for (t = 0; t < 32; t++)
                {
                    printf("%2x, ", debug_buf[t]);
                }
                hwl_delay_ms(5);
            }
        }
        else if (strncmp("shadow dump", (const char *)debug_buf, 11) == 0)
        {
            su16 tmp = 0;
            printf("[DEBUG] Dump Shadow.\r\n    ");
            for (tmp = 0; tmp < 32; tmp++)
            {
                printf("%2d  ", tmp);
            }
            for (tmp = 0; tmp < 8; tmp++)
            {
                unsigned short t = 0;
                printf("\r\n%3d:", tmp * 32);
                for (t = 0; t < 32; t++)
                {
                    printf("%2x, ", gCfg_u.memory[t + tmp * 32]);
                }
                hwl_delay_ms(5);
            }
        }
        else if (strncmp("compare", (const char *)debug_buf, 7) == 0)
        {
            printf("[DEBUG] Compare.\r\n");
            for (debug_cnt = 0; debug_cnt < 8; debug_cnt++)
            {
                unsigned short t = 0;
                hwl_iic_read(debug_cnt * 32, debug_buf, 32);
                for (t = 0; t < 32; t++)
                {

#define CUR_INDEX (t + debug_cnt * 32)
#define IN_RANGE(head, type) ((CUR_INDEX >= head) && (CUR_INDEX < sizeof(type) + head))

                    if (IN_RANGE(CONFIG_MAP_COMMON_HEAD, Config_Common) ||
                        IN_RANGE(CONFIG_MAP_MODE_HEAD, Config_Mode) ||
                        IN_RANGE(CONFIG_MAP_MODEFACTORY_HEAD, Config_ModeFactory) ||
                        IN_RANGE(CONFIG_MAP_FACTORY_HEAD, Config_Factory) ||
                        IN_RANGE(CONFIG_MAP_FIRMWARE_HEAD, Config_Firmware) ||
                        IN_RANGE(CONFIG_MAP_WIRELESS_HEAD, Config_Wireless))
                    {
                        if (gCfg_u.memory[t + debug_cnt * 32] != debug_buf[t])
                        {
                            printf("On [%d] Not Match: RAM: 0x%x , EEPROM: 0x%x \r\n", t + debug_cnt * 32, gCfg_u.memory[t + debug_cnt * 32], debug_buf[t]);
                        }
                    }
                }
                hwl_delay_ms(5);
            }
        }
        else if ((strncmp("set", (const char *)debug_buf, 3) == 0))
        {
            char *sPtr = 0;
            char *token;
            su8 buf[16];
            su8 totalNum = 0;
            su16 ii = 0;
            const char s[2] = " ";

            SF_Boolen isOkToProcessAsNumber;
            token = my_strtok((char *)debug_buf, s);
            while (token != 0)
            {
                sPtr = token;
                isOkToProcessAsNumber = SF_True;
                ii = 0;
                while (*sPtr != '\0' && sPtr != 0)
                {

                    if ((*sPtr == '\r') || (*sPtr == '\n'))
                    {
                        *sPtr = '\0';
                        break;
                    }
                    if (*sPtr < '0' || *sPtr > '9')
                    {
                        isOkToProcessAsNumber = SF_False;
                        break;
                    }
                    sPtr++;
                    ii++;
                }

                if (isOkToProcessAsNumber && ii >= 1)
                {
                    buf[totalNum] = (su8)my_atoi(token);
                    totalNum++;
                }

                token = my_strtok(0, s);
            }
            if (totalNum <= 1)
            {
                printf("[DEBUG] parms error:too few input.\r\n");
            }
            else
            {
                printf("[DEBUG] Set REG [%d...] = {", buf[0]);
                for (ii = 0; ii < totalNum - 1; ii++)
                {
                    printf("%d, ", buf[ii + 1]);
                    gCfg_u.memory[buf[0] + ii] = buf[1 + ii];
                }
                printf("}.\r\n");
            }
        }
        else if (strncmp("flush mf", (const char *)debug_buf, 8) == 0)
        {
            config_flush(CONFIG_MODEFACTORY);
            printf("[DEBUG] CONFIG MODEFACTORY flushed.\r\n");
        }
        else if (strncmp("flush md", (const char *)debug_buf, 8) == 0)
        {
            config_flush(CONFIG_MODE);
            printf("[DEBUG] CONFIG MODE flushed.\r\n");
        }
        else if (strncmp("flush cm", (const char *)debug_buf, 8) == 0)
        {
            config_flush(CONFIG_COMMON);
            printf("[DEBUG] CONFIG COMMON flushed.\r\n");
        }
        else if (strncmp("flush fa", (const char *)debug_buf, 8) == 0)
        {
            config_flush(CONFIG_FACTORY);
            printf("[DEBUG] CONFIG FACTORY flushed.\r\n");
        }
        else if (strncmp("flush fi", (const char *)debug_buf, 8) == 0)
        {
            config_flush(CONFIG_FIRMWARE);
            printf("[DEBUG] CONFIG FIRMWARE flushed.\r\n");
        }
        else if (strncmp("flush wi", (const char *)debug_buf, 8) == 0)
        {
            config_flush(CONFIG_WIRELESS);
            printf("[DEBUG] CONFIG WIRELESS flushed.\r\n");
        }
        else if (strncmp("adc", (const char *)debug_buf, 3) == 0)
        {
            if (hwl_adc_isConvertFinished() == SF_True)
            {
                hwl_adc_start();
                while (hwl_adc_isConvertFinished() == SF_False);
                printf("%4d ", hwl_adc_getValue()>>4);
            }
        }
        else if (strncmp("debug info", (const char *)debug_buf, 10) == 0)
        {
            debug_en = 0xAA;
            debug_level = DEBUG_INFO;
            DEBUG_SAVE_EN(debug_en);
            hwl_delay_ms(5);
            DEBUG_SAVE_LEVEL(debug_level);
        }
        else if (strncmp("debug warn", (const char *)debug_buf, 10) == 0)
        {
            debug_en = 0xAA;
            debug_level = DEBUG_WARN;
            DEBUG_SAVE_EN(debug_en);
            hwl_delay_ms(5);
            DEBUG_SAVE_LEVEL(debug_level);
        }
        else if (strncmp("debug error", (const char *)debug_buf, 11) == 0)
        {
            debug_en = 0xAA;
            debug_level = DEBUG_ERROR;
            DEBUG_SAVE_EN(debug_en);
            hwl_delay_ms(5);
            DEBUG_SAVE_LEVEL(debug_level);
        }
        else if (strncmp("debug none", (const char *)debug_buf, 10) == 0)
        {
            debug_en = 0xFF;
            debug_level = DEBUG_NONE;
            DEBUG_SAVE_EN(debug_en);
            hwl_delay_ms(5);
            DEBUG_SAVE_LEVEL(debug_level);
        }
        else if (debug_buf[0] == '\r' || debug_buf[0] == '\n')
        {
        }
        else
        {
            if (strncmp("help", (const char *)debug_buf, 4) == 0)
            {
                printf("help:\r\n");
                printf("\tdebug info/warn/error/none: debug level\r\n");
                printf("\teeprom erase: Clear EEPROM.\r\n");
                printf("\teeprom dump: Dump EEPROM values.\r\n");
                printf("\tshadow dump: Dump Shadow values.\r\n");
                printf("\tcompare: compare the diff between Shadow and eeprom.\r\n");
                printf("\tset [start address] [val1] [val2] ... decimal values.\r\n");
                printf("\tflush md: flushing mode to EEPROM.\r\n");
                printf("\t      mf: modefactory.\r\n");
                printf("\t      cm: common.\r\n");
                printf("\t      fa: factory.\r\n");
                printf("\t      fi: firmware.\r\n");
                printf("\t      wi: wireless.\r\n");
                printf("\tadc : dump adc value.\r\n");
            }
            else
            {
                printf("[DEBUG] cmd error,type \"help\" for command information.\r\n");
            }
        }
    }
}

void debug_task(void)
{
    if (SET == usart_flag_get(USART0, USART_FLAG_RBNE))
    {
        if (debug_cnt < 32)
        {
            debug_buf[debug_cnt] = usart_data_receive(USART0);
            while (RESET == usart_flag_get(USART0, USART_FLAG_TBE))
                ;
            if (isCmdEnable)
            {
                usart_data_transmit(USART0, (uint8_t)debug_buf[debug_cnt]);
            }

            debug_cnt++;
        }
    }
    //删除符号
    if (debug_cnt > 0)
    {
        if (debug_buf[debug_cnt - 1] == '\n' || debug_buf[debug_cnt - 1] == '\r')
        {
            printf("\r\n");
            debu_process();
            printf("\r\n>>");
            for (debug_cnt = 0; debug_cnt < 32; debug_cnt++)
            {
                debug_buf[debug_cnt] = 0;
            }
            debug_cnt = 0;
        }
        if (debug_cnt == 32)
        {
            debug_cnt = 0;
        }
    }
}

void debug_init(void)
{
    /*用于调试*/
    /* 使能 GPIOA 时钟 */
    rcu_periph_clock_enable(RCU_GPIOA); //使能GPIO口，否则可能会有问题
    //step1: serial init baud 115200
    rcu_periph_clock_enable(RCU_USART0);        //使能串口0时钟线
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_9);  //设置GPIO9为TX 复用功能
    gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_10); //设置GPIO10为RX 复用功能

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);             //设置TX口上拉
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_9); //设置TX口速度为10Mhz 推挽

    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);             //设置RX口上拉
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_10); //设置RX口速度为10Mhz 推挽（照抄官方）

    usart_deinit(USART0);
    usart_baudrate_set(USART0, 115200U); //设置波特率为115200
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_enable(USART0);
    //step2:redirect printf to serial port 0

    //step3: led debug init
    hwl_gpio_set(HWL_PIN_LED1, HWL_OUTPUT);
    //由于调试比较特殊，所以允许访问一些底层寄存器
    DEBUG_LOAD();
}

/* 加入以下代码,支持printf函数,而不需要选择use MicroLIB	*/
/* 重定义fputc函数 */
int fputc(int ch, FILE *f)
{
    while (RESET == usart_flag_get(USART0, USART_FLAG_TBE))
        ;
    usart_data_transmit(USART0, (uint8_t)ch);
    return ch;
}

//0 短亮，1 长亮
void i_dashdot(unsigned char dashDot)
{
    if (dashDot)
    {
        hwl_delay_ms(100);
    }
    else
    {
        hwl_delay_ms(50);
    }
    hwl_gpio_set(HWL_PIN_LED1, HWL_HIGH);
    if (dashDot)
    {
        hwl_delay_ms(500);
    }
    else
    {
        hwl_delay_ms(50);
    }
    hwl_gpio_set(HWL_PIN_LED1, HWL_LOW);
    if (dashDot)
    {
        hwl_delay_ms(100);
    }
    else
    {
        hwl_delay_ms(50);
    }
}
//使用莫尔斯码表示数字
void i_ledFlash(unsigned char num)
{
    unsigned char tm = num;
    if (num <= 5)
    {
        while (num--)
        {
            i_dashdot(0);
        }
        tm = 5 - tm;
        while (tm--)
        {
            i_dashdot(1);
        }
    }
    else if (num <= 9)
    {
        num = 10 - num;
        tm = 5 - num;
        while (tm--)
        {
            i_dashdot(1);
        }
        while (num--)
        {
            i_dashdot(0);
        }
    }
}

void debug_led(unsigned char ERRORCODE)
{
    unsigned char tm;
    tm = (ERRORCODE % 100) / 10;
    i_ledFlash(tm);
    hwl_delay_ms(700);
    tm = ERRORCODE % 10;
    i_ledFlash(tm);
    hwl_delay_ms(1500);
}
#endif